/**
    @file util.h
    @brief Lots of utilities and defination used by the compiler like generic data structure.
    
    Defined some useful macro, and have utilities below:<br>
    U_set    <br>
    U_setstack    <br>
    U_stack    <br>
    U_nbList    <br>
    U_edgeSet    <br>
*/
/**    @defgroup utility Utility
    The Module of the utility.
*/

#ifndef __UTILS_H__
#define __UTILS_H__

#include <assert.h>

#if   defined(_MSC_VER) && (_MSC_VER>1000)
#pragma warning(disable:4996)
include <conio.h>
#endif

///For C have not string type, I defined one my self
typedef char *string;
///Define a bool so that we can code like C++
#define bool char

#ifndef NULL
#define NULL 0
#endif

#define TRUE 1
#define FALSE 0

#ifndef RESULT_OK
#define RESULT_OK    0
#endif
#ifndef RESULT_ERROR
#define RESULT_ERROR    1
#endif

///Macro used to pause the program at the end ot the main function
#define U_mainEnd() printf("Press any key to continue..."); getch();

#define MAX_LINK_SIZE 16

///New malloc function that will panic if the malloc function returns 0
void *checked_malloc(int);

///Create a new string
string String(char *);

typedef struct U_boolList_ *U_boolList;
struct U_boolList_ {bool head; U_boolList tail;};
U_boolList U_BoolList(bool head, U_boolList tail);

/////////////////////////////////////////////////////////////////////
/** @defgroup set Set Utility
 * @ingroup utility
 * The set utility is used to do the set algebra calculation.
 * @{
 */

///The U_set structure
typedef struct U_set_* U_set;
///U_setItem is the element stored in U_set
typedef struct U_setItem_* U_setIter;

///Create a new U_set
U_set U_setNew();
///Free the memory
void U_setDestroy(U_set* s);

/** Add a with b and save it in result. The set result should be a valid
 * pointer returned by U_setNew()
 * @param a set a
 * @param b set b
 * @param result where the final result saves
 * @return count of elements in result
 */
int U_setAdd3(U_set result, U_set a, U_set b); ///< result = a+b;
int U_setSub3(U_set result, U_set a, U_set b); ///< result = a-b;
int U_setCross3(U_set result, U_set a, U_set b); ///< result = a^b;
/** Add a with b and save the result to a.
 * @param a set a
 * @param b set b
 * @return count of elements in set a
 */
int U_setAdd2(U_set a, U_set b);         ///< a = a+b;
int U_setSub2(U_set a, U_set b);         ///< a = a-b;

/** Insert data into a set.
 * @param data pointer to be saved
 * @param result where you wanna the data be saved
 * @return It returns 0 if the data is already in the set, 1 if it's newly
 * added
 */
int U_setInsert(U_set result, void* data); 
int U_setRemove(U_set result, void* data); ///< Remove a data from a set
void U_setClear(U_set a);

void*    U_setLookup(U_set a, int index); ///< Get the data of the interator

/// Get the count of the elements in the set
int U_setGetCount(U_set s); 
int U_setIsEmpty(U_set s);

/// Get a copy of a given set
int U_setClone(U_set des, U_set src); 

/// Print a set in the standard io
void U_setPrint(U_set s); 

/// Whether the set have the given element
bool U_setHas(U_set set, void* data); 

/// Function type for interator callback
typedef int (*iterFunc)(void* data);
typedef iterFunc setIterFunc;

/** For each element in the given set, the function f will be called.
 * @param s Set to run the function
 * @param f Function pointer to witch you wanna run
 */
void U_setForEach(U_set s, setIterFunc f);
// eof U_set
/// @}
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
/** @defgroup setstack Set Stack
 * @ingroup utility
 * The utility setstack is a stack based on set utility. It can be manipulated
 * as a stack, and also you can retrive a set structure containing all the 
 * elements of the stack.<br>
 * <strong>WARNING: DO NOT manipulat the U_set structure returned by 
 * U_setstackGetSet,</strong> or you are likely to crash the setstack.
 * @{
 */
/// setstack type
typedef struct U_setstack_* U_setstack;
typedef struct U_setstackItem_* U_setstackItem;

/// Create a new setstack
U_setstack    U_setstackNew();

/// Destroy a setstack
void        U_setstackDestroy(U_setstack stack);

/// Push a data into the stack
int        U_setstackPush(U_setstack stack, void *data);

/// Pop a data from the stack
void*        U_setstackPop(U_setstack stack);

/// Get the count of the elements in the stack
int        U_setstackCount(U_setstack stack);

/// Get a set holding all the elements in the stack
U_set        U_setstackGetSet(U_setstack stack);

/// Get a copy a given stack
U_set        U_setstackCloneSet(U_setstack stack);
/// @}
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
/** @defgroup stack Stack
 * @ingroup utility
 * A stack utility uses array. It's not able to get a set directly.
 * @{
 */
/// stack type
typedef struct U_stack_* U_stack;
typedef struct U_stackItem_* U_stackIter;

/// stack callback function pointer
typedef iterFunc stackIterFunc;

U_stack U_stackNew();             ///< Create a new stack
void    U_stackDestroy(U_stack stack);  ///< Destroy a stack

/// Push a element into the stack
int    U_stackPush(U_stack stack, void *data);

/// Pop a element from the stack
void*    U_stackPop(U_stack stack);

/// Get the count of the elements in the stack
int    U_stackCount(U_stack stack); 

/// Have the iterator go for the next element
void    U_stackWalk(U_stackIter* iter);

/// Retrieve the data of the iterator
void*    U_stackLookup(U_stackIter iter);

/// Get the iterator of the stack
U_stackIter U_stackGetIter(U_stack stack);

/// Run function on every element in the stack
void U_stackForEach(U_stack s, stackIterFunc f);
/// @}
/////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////
//
typedef void*  U_nbListNode;
typedef struct U_nbListItem_ *U_nbListItem;
typedef struct U_nbList_ *U_nbList;
U_nbList U_nbListNew();
void  U_nbListDestroy(U_nbList list);
int   U_nbListEnter(U_nbList list, U_nbListNode node);
void  U_nbListAddEdge(U_nbList list, U_nbListNode n1, U_nbListNode n2);

/// TODO: Rename it to U_nbListNodeCount, and add a function U_nbListEdgeCount
int   U_nbListCount(U_nbList list);
bool  U_nbListIsAdj(U_nbList list, U_nbListNode n1, U_nbListNode n2);
bool  U_nbListIsAdjK(U_nbList list, int n1, int n2);
int   U_nbListGetKey(U_nbList list, U_nbListNode node);
void* U_nbListGetPtr(U_nbList list, int key);
void  U_nbListClear();
//
/////////////////////////////////////////////////////////////////////

typedef struct U_edgeSet_ *U_edgeSet;
U_edgeSet U_edgeSetNew();
void U_edgeSetDestroy();
void U_edgeSetEnter(U_edgeSet p, void *n);
void U_edgeSetAddEdge(U_edgeSet p, void *n1, void *n2);
bool U_edgeSetIsAdj(U_edgeSet p, void *n1, void *n2);


#endif

